package com.stone.framework.batch.service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.stone.framework.batch.entity.CaseAssign;
import com.stone.framework.batch.entity.CaseInfo;
import com.stone.framework.batch.entity.CaseState;
import com.stone.framework.batch.entity.Team;
import com.stone.framework.batch.model.CaseAllocBO;
import com.stone.framework.batch.model.CaseAllocResultBO;
import com.stone.framework.core.util.Beans;

public abstract class AbstractCaseService implements CaseService {

    private List<CaseInfo> closedCaseInfoList = new ArrayList<>();

    private List<CaseInfo> newCaseInfoList = new ArrayList<>();

    private List<CaseState> updateCaseStateList = new ArrayList<>();

    private List<CaseState> newCaseStateList = new ArrayList<>();

    private List<CaseAssign> closedCaseAssignList = new ArrayList<>();

    private List<CaseAssign> newCaseAssignList = new ArrayList<>();

    @Override
    public void allocate(CaseAllocBO caseAllocBo) {
        CaseInfo currCaseInfo = this.queryCurrCaseInfo(caseAllocBo);
        CaseAllocResultBO resultBo = doAllocate(currCaseInfo, caseAllocBo);
        update(resultBo.getClosedCaseInfo(), resultBo.getNewCaseInfo(), resultBo.getUpdateCaseState(),
            resultBo.getNewCaseState(), resultBo.getClosedCaseAssign(), resultBo.getNewCaseAssign());
    }

    @Override
    public void allocate(List<CaseAllocBO> list) {
        list.stream().forEach(caseAllocBo -> {
            CaseInfo currCaseInfo = this.queryCurrCaseInfo(caseAllocBo);
            CaseAllocResultBO resultBo = doAllocate(currCaseInfo, caseAllocBo);
            dealResultBO(resultBo);
        });
        batchUpdate(closedCaseInfoList, newCaseInfoList, updateCaseStateList, newCaseStateList, closedCaseAssignList,
            newCaseAssignList);
    }

    protected abstract CaseInfo queryCurrCaseInfo(CaseAllocBO caseAllocBo);

    protected abstract CaseAllocResultBO doAllocate(CaseInfo currCaseInfo, CaseAllocBO caseAllocBo);

    protected abstract void batchUpdate(List<CaseInfo> closedCaseInfoList, List<CaseInfo> newCaseInfoList,
        List<CaseState> updateCaseStateList, List<CaseState> newCaseStateList, List<CaseAssign> closedCaseAssignList,
        List<CaseAssign> newCaseAssignList);

    protected abstract void update(CaseInfo closedCaseInfo, CaseInfo newCaseInfo, CaseState updateCaseState,
        CaseState newCaseState, CaseAssign closedCaseAssign, CaseAssign newCaseAssign);

    protected abstract Team getTeam(String teamCode);

    protected final CaseInfo buildClosedCaseInfo(CaseInfo currCaseInfo) {
        return currCaseInfo;
    }

    protected final CaseInfo buildNewCaseInfo(CaseAllocBO caseAllocBo, CaseInfo currCaseInfo) {
        CaseInfo caseInfo = new CaseInfo();

        Beans.buildCommonEntity(caseInfo);
        caseInfo.setOrgCode(caseAllocBo.getOrgCode());
        caseInfo.setProjectCode(caseAllocBo.getProjectCode());
        caseInfo.setEventCode(caseAllocBo.getEventCode());
        caseInfo.setBatchCode(caseAllocBo.getBatchCode());

        caseInfo.setCaseNbr(caseAllocBo.getCaseNbr());
        caseInfo.setCustNbr(caseAllocBo.getCustNbr());
        caseInfo.setCustName(caseAllocBo.getCustName());
        caseInfo.setTeamCode(caseAllocBo.getTeamCode());
        caseInfo.setInTeamDate(LocalDateTime.now());
        // Team team = this.getTeam(caseAllocBo.getTeamCode());
        // caseInfo.setDeptId(team == null ? null : team.getDeptId());
        caseInfo.setDeptId(caseAllocBo.getDeptId());

        if (caseAllocBo.getCollector() != null) {
            caseInfo.setCollector(caseAllocBo.getCollector());
            caseInfo.setInUserDate(LocalDateTime.now());
        }

        if (currCaseInfo != null) { // 存量案件
            caseInfo.setPreTeamCode(currCaseInfo.getTeamCode());
            caseInfo.setPreCollector(currCaseInfo.getCollector());
            caseInfo.setPreDeptId(currCaseInfo.getDeptId());
        }

        return caseInfo;
    }

    protected final CaseState buildUpdateCaseState(CaseInfo caseInfo, CaseState.State state) {
        CaseState caseState = new CaseState();
        Beans.copyDebtProperties(caseInfo, caseState);
        Beans.buildCommonEntity(caseState);

        caseState.setCaseNbr(caseInfo.getCaseNbr());
        // caseState.setCustNbr(caseInfo.getCustNbr());

        caseState.setState(state);
        boolean isExit = Arrays.asList(CaseState.State.END, CaseState.State.CANCEL, CaseState.State.QUIT).stream()
            .anyMatch(s -> s.equals(state));
        if (isExit) { // 出催
            caseState.setLastExitDate(LocalDateTime.now());
        }

        return caseState;
    }

    protected final CaseState buildNewCaseState(CaseInfo currCaseInfo, CaseAllocBO caseAllocBo) { // merge into
        CaseState caseState = new CaseState();
        Beans.buildCommonEntity(caseState);
        caseState.setOrgCode(caseAllocBo.getOrgCode());
        caseState.setProjectCode(caseAllocBo.getProjectCode());
        caseState.setEventCode(caseAllocBo.getEventCode());
        caseState.setBatchCode(caseAllocBo.getBatchCode());

        caseState.setCaseNbr(caseAllocBo.getCaseNbr());
        caseState.setCustNbr(caseAllocBo.getCustNbr());
        caseState.setCustName(caseAllocBo.getCustName());
        caseState.setStartDate(caseAllocBo.getStartDate());
        caseState.setEndDate(caseAllocBo.getEndDate());
        caseState.setState(caseAllocBo.getCollector() == null ? CaseState.State.UNALLOC : CaseState.State.ALLOC);
        if (currCaseInfo == null) {
            caseState.setLastEntryDate(LocalDateTime.now());
        }

        return caseState;
    }

    protected final CaseAssign buildClosedCaseAssign(CaseInfo currCaseInfo, CaseAssign.Type type) {
        CaseAssign caseAssign = new CaseAssign();

        Beans.buildCommonEntity(caseAssign);
        Beans.copyDebtProperties(currCaseInfo, caseAssign);
        caseAssign.setEndType(type);
        caseAssign.setEndDate(LocalDateTime.now());

        return caseAssign;
    }

    protected final CaseAssign buildNewCaseAssign(CaseInfo newCaseInfo, CaseAllocBO caseAllocBo, CaseAssign.Type type) {
        CaseAssign caseAssign = new CaseAssign();
        Beans.copyDebtProperties(newCaseInfo, caseAssign);
        Beans.buildCommonEntity(caseAssign);

        caseAssign.setCaseNbr(newCaseInfo.getCaseNbr());
        caseAssign.setCustNbr(newCaseInfo.getCustNbr());
        caseAssign.setTeamCode(newCaseInfo.getTeamCode());
        caseAssign.setCollector(newCaseInfo.getCollector());
        caseAssign.setDeptId(newCaseInfo.getDeptId());
        caseAssign.setPreTeamCode(newCaseInfo.getPreTeamCode());
        caseAssign.setPreCollector(newCaseInfo.getPreCollector());
        caseAssign.setPreDeptId(newCaseInfo.getPreDeptId());

        caseAssign.setAllocType(type);
        caseAssign.setStartDate(CaseAssign.Type.NEW.equals(type) ? LocalDateTime.now() : null);
        caseAssign.setReason(caseAllocBo.getReason());
        caseAssign.setTotBal(caseAllocBo.getTotBal());
        caseAssign.setTotDebt(caseAllocBo.getTotDebt());

        return caseAssign;
    }

    /**
     * 将分案结果BO转换为对应List
     * 
     * @param resultBo
     */
    private void dealResultBO(CaseAllocResultBO resultBo) {
        if (resultBo.getClosedCaseInfo() != null) {
            closedCaseInfoList.add(resultBo.getClosedCaseInfo());
        }
        if (resultBo.getNewCaseInfo() != null) {
            newCaseInfoList.add(resultBo.getNewCaseInfo());
        }
        if (resultBo.getClosedCaseAssign() != null) {
            closedCaseAssignList.add(resultBo.getClosedCaseAssign());
        }
        if (resultBo.getNewCaseAssign() != null) {
            newCaseAssignList.add(resultBo.getNewCaseAssign());
        }
        if (resultBo.getUpdateCaseState() != null) {
            updateCaseStateList.add(resultBo.getUpdateCaseState());
        }
        if (resultBo.getNewCaseState() != null) {
            newCaseStateList.add(resultBo.getNewCaseState());
        }
    }

}
